﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace GoodStuff.Diagnostics
{
    /// <summary>
    /// Work in progress. Not stable!
    /// </summary>
    public static class TraceHelper
    {
        [ThreadStatic]
        public static TraceHelperEntry helperTop = null;

        [IgnoreTraceHelper]
        public static TraceHelperEntry Push()
        {
            helperTop = new TraceHelperEntry(helperTop);
            return helperTop;
        }

        public static string GetInfo()
        {
            if (helperTop != null)
            {
                //return all info, recursively.
                return helperTop.GetInfo();
            }
            return null;
        }
    }

    public class IgnoreTraceHelperAttribute : Attribute
    {
    }
    
    public class TraceHelperEntry : IDisposable
    {
        TraceHelperEntry _parent;
        StackFrame _currentFrame;

        [IgnoreTraceHelper]
        public TraceHelperEntry(TraceHelperEntry parent)
        {
            _parent = parent;  
            StackTrace st = new StackTrace();
            int i = 0;

            StackFrame frame = st.GetFrame(0);
            while (i < st.FrameCount)
            {
                if (frame.GetMethod().GetAttribute<IgnoreTraceHelperAttribute>() == null)
                {
                    break;
                }
                i++;
                frame = st.GetFrame(i);                
            }

            _currentFrame = frame;
                      
        }

        public void Dispose()
        {
            Trace.WriteLine("Exit" + this.ToString());

            //roll back the TraceHelper
            TraceHelper.helperTop = this._parent;
        }

        public override string ToString()
        {
            return _currentFrame.ToString();
        }

        public string GetInfo()
        {
            string result = string.Empty;
            if (_parent != null)
            {
                result = _parent.GetInfo() + Environment.NewLine;
            }
            return result + this.ToString();
        }
    }
}
